home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / share / apps / dcopidlng / kdocAstUtil.pm < prev    next >
Text File  |  2005-09-10  |  10KB  |  537 lines

  1. =head1 kdocAstUtil
  2.  
  3.     Utilities for syntax trees.
  4.  
  5. =cut
  6.  
  7.  
  8. package kdocAstUtil;
  9.  
  10. use Ast;
  11. use Carp;
  12. use File::Basename;
  13. use kdocUtil;
  14. use Iter;
  15. use strict;
  16.  
  17. use vars qw/ $depth $refcalls $refiters @noreflist %noref /;
  18.  
  19. sub BEGIN {
  20. # statistics for findRef
  21.  
  22.     $depth = 0;
  23.     $refcalls = 0;
  24.     $refiters = 0;
  25.  
  26. # findRef will ignore these words
  27.  
  28.     @noreflist = qw( const int char long double template 
  29.         unsigned signed float void bool true false uint 
  30.         uint32 uint64 extern static inline virtual operator );
  31.  
  32.     foreach my $r ( @noreflist ) {
  33.         $noref{ $r } = 1;
  34.     }
  35. }
  36.  
  37.  
  38. =head2 findRef
  39.  
  40.     Parameters: root, ident, report-on-fail
  41.     Returns: node, or undef
  42.  
  43.     Given a root node and a fully qualified identifier (:: separated),
  44.     this function will try to find a child of the root node that matches
  45.     the identifier.
  46.  
  47. =cut
  48.  
  49. sub findRef
  50. {
  51.     my( $root, $name, $r ) = @_;
  52.  
  53.     confess "findRef: no name" if !defined $name || $name eq "";
  54.  
  55.     $name =~ s/\s+//g;    
  56.     return undef if exists $noref{ $name };
  57.  
  58.     $name =~ s/^#//g;
  59.  
  60.     my ($iter, @tree) = split /(?:\:\:|#)/, $name;
  61.     my $kid;
  62.  
  63.     $refcalls++;
  64.  
  65.     # Upward search for the first token
  66.     return undef if !defined $iter;
  67.  
  68.     while ( !defined findIn( $root, $iter ) ) {
  69.         return undef if !defined $root->{Parent};
  70.         $root = $root->{Parent};
  71.     }
  72.     $root = $root->{KidHash}->{$iter};
  73.     carp if !defined $root;
  74.  
  75.     # first token found, resolve the rest of the tree downwards
  76.     foreach $iter ( @tree ) {
  77.         confess "iter in $name is undefined\n" if !defined $iter;
  78.         next if $iter =~ /^\s*$/;
  79.  
  80.         unless ( defined findIn( $root, $iter ) ) {
  81.             confess "findRef: failed on '$name' at '$iter'\n"
  82.                 if defined $r;
  83.             return undef;
  84.         }
  85.  
  86.         $root = $root->{KidHash}->{ $iter };    
  87.         carp if !defined $root;
  88.     }
  89.  
  90.     return $root;
  91. }
  92.  
  93. =head2 findIn
  94.  
  95.     node, name: search for a child
  96.  
  97. =cut
  98.  
  99. sub findIn
  100. {
  101.     return undef unless defined $_[0]->{KidHash};
  102.  
  103.     my $ret =  $_[0]->{KidHash}->{ $_[1] };
  104.  
  105.     return $ret;
  106. }
  107.  
  108.  
  109. #
  110. # Inheritance utilities
  111. #
  112.  
  113. =head2 makeInherit
  114.  
  115.     Parameter: $rootnode, $parentnode
  116.  
  117.     Make an inheritance graph from the parse tree that begins
  118.     at rootnode. parentnode is the node that is the parent of
  119.     all base class nodes.
  120.  
  121. =cut
  122.  
  123. sub makeInherit
  124. {
  125.     my( $rnode, $parent ) = @_;
  126.  
  127.     foreach my $node ( @{ $rnode->{Kids} } ) {
  128.         next if !defined $node->{Compound};
  129.  
  130.         # set parent to root if no inheritance
  131.  
  132.         if ( !exists $node->{InList} ) {
  133.             newInherit( $node, "Global", $parent );
  134.             $parent->AddPropList( 'InBy', $node );
  135.  
  136.             makeInherit( $node, $parent );
  137.             next;
  138.         }
  139.  
  140.         # link each ancestor
  141.         my $acount = 0;
  142. ANITER:
  143.         foreach my $in ( @{ $node->{InList} } ) {
  144.             unless ( defined $in ) {
  145.                 Carp::cluck "warning: $node->{astNodeName} "
  146.                     ." has undef in InList.";
  147.                 next ANITER;
  148.             }
  149.  
  150.             my $ref = kdocAstUtil::findRef( $rnode, 
  151.                     $in->{astNodeName} );
  152.  
  153.             if( !defined $ref ) {
  154.                 # ancestor undefined
  155.                 warn "warning: ", $node->{astNodeName},
  156.                     " inherits unknown class '",
  157.                         $in->{astNodeName},"'\n";
  158.  
  159.                 $parent->AddPropList( 'InBy', $node );
  160.             }
  161.             else {
  162.                 # found ancestor
  163.                 $in->AddProp( "Node", $ref );
  164.                 $ref->AddPropList( 'InBy', $node );
  165.                 $acount++;
  166.             }
  167.         }
  168.  
  169.         if ( $acount == 0 ) {
  170.             # inherits no known class: just parent it to global
  171.             newInherit( $node, "Global", $parent );
  172.             $parent->AddPropList( 'InBy', $node );
  173.         }
  174.         makeInherit( $node, $parent );
  175.     }
  176. }
  177.  
  178. =head2 newInherit
  179.  
  180.     p: $node, $name, $lnode?
  181.  
  182.     Add a new ancestor to $node with raw name = $name and
  183.     node = lnode.
  184. =cut
  185.  
  186. sub newInherit
  187. {
  188.     my ( $node, $name, $link ) = @_;
  189.  
  190.     my $n = Ast::New( $name );
  191.     $n->AddProp( "Node", $link ) unless !defined $link;
  192.  
  193.     $node->AddPropList( "InList", $n );
  194.     return $n;
  195. }
  196.  
  197. =head2 inheritName
  198.  
  199.     pr: $inheritance node.
  200.  
  201.     Returns the name of the inherited node. This checks for existence
  202.     of a linked node and will use the "raw" name if it is not found.
  203.  
  204. =cut
  205.  
  206. sub inheritName
  207. {
  208.     my ( $innode ) = @_;
  209.  
  210.     return defined $innode->{Node} ? 
  211.         $innode->{Node}->{astNodeName}
  212.         : $innode->{astNodeName};
  213. }
  214.  
  215. =head2 inheritedBy
  216.  
  217.     Parameters: out listref, node
  218.  
  219.     Recursively searches for nodes that inherit from this one, returning
  220.     a list of inheriting nodes in the list ref.
  221.  
  222. =cut
  223.  
  224. sub inheritedBy
  225. {
  226.     my ( $list, $node ) = @_;
  227.  
  228.     return unless exists $node->{InBy};
  229.  
  230.     foreach my $kid ( @{ $node->{InBy} } ) {
  231.         push @$list, $kid;
  232.         inheritedBy( $list, $kid );
  233.     }
  234. }
  235.  
  236. =head2 hasLocalInheritor
  237.  
  238.     Parameter: node
  239.     Returns: 0 on fail
  240.  
  241.     Checks if the node has an inheritor that is defined within the
  242.     current library. This is useful for drawing the class hierarchy,
  243.     since you don't want to display classes that have no relationship
  244.     with classes within this library.
  245.  
  246.     NOTE: perhaps we should cache the value to reduce recursion on 
  247.     subsequent calls.
  248.  
  249. =cut
  250.  
  251. sub hasLocalInheritor
  252. {
  253.     my $node = shift;
  254.  
  255.     return 0 if !exists $node->{InBy};
  256.  
  257.     my $in;
  258.     foreach $in ( @{$node->{InBy}} ) {
  259.         return 1 if !exists $in->{ExtSource}
  260.             || hasLocalInheritor( $in );
  261.     }
  262.  
  263.     return 0;
  264. }
  265.  
  266.  
  267.  
  268. =head2 allMembers
  269.  
  270.     Parameters: hashref outlist, node, $type
  271.  
  272.     Fills the outlist hashref with all the methods of outlist,
  273.     recursively traversing the inheritance tree.
  274.  
  275.     If type is not specified, it is assumed to be "method"
  276.  
  277. =cut
  278.  
  279. sub allMembers
  280. {
  281.     my ( $outlist, $n, $type ) = @_;
  282.     my $in;
  283.     $type = "method" if !defined $type;
  284.  
  285.     if ( exists $n->{InList} ) {
  286.  
  287.         foreach $in ( @{$n->{InList}} ) {
  288.             next if !defined $in->{Node};
  289.             my $i = $in->{Node};
  290.  
  291.             allMembers( $outlist, $i ) 
  292.                 unless $i == $main::rootNode;
  293.         }
  294.     }
  295.  
  296.     return unless exists $n->{Kids};
  297.  
  298.     foreach $in ( @{$n->{Kids}} ) {
  299.         next if $in->{NodeType} ne $type;
  300.  
  301.         $outlist->{ $in->{astNodeName} } = $in;
  302.     }
  303. }
  304.  
  305. =head2 findOverride
  306.  
  307.     Parameters: root, node, name
  308.  
  309.     Looks for nodes of the same name as the parameter, in its parent
  310.     and the parent's ancestors. It returns a node if it finds one.
  311.  
  312. =cut
  313.  
  314. sub findOverride
  315. {
  316.     my ( $root, $node, $name ) = @_;
  317.     return undef if !exists $node->{InList};
  318.  
  319.     foreach my $in ( @{$node->{InList}} ) {
  320.         my $n = $in->{Node};
  321.         next unless defined $n && $n != $root && exists $n->{KidHash};
  322.  
  323.         my $ref  = $n->{KidHash}->{ $name };
  324.         
  325.         return $n if defined $ref && $ref->{NodeType} eq "method";
  326.  
  327.         if ( exists $n->{InList} ) {
  328.             $ref = findOverride( $root, $n, $name );
  329.             return $ref if defined $ref;
  330.         }
  331.     }
  332.  
  333.     return undef;
  334. }
  335.  
  336. =head2 attachChild
  337.  
  338.     Parameters: parent, child
  339.  
  340.     Attaches child to the parent, setting Access, Kids
  341.     and KidHash of respective nodes.
  342.  
  343. =cut
  344.  
  345. sub attachChild
  346. {
  347.     my ( $parent, $child ) = @_;
  348.     confess "Attempt to attach ".$child->{astNodeName}." to an ".
  349.         "undefined parent\n" if !defined $parent;
  350.  
  351.     $child->AddProp( "Access", $parent->{KidAccess} );
  352.     $child->AddProp( "Parent", $parent );
  353.  
  354.     $parent->AddPropList( "Kids", $child );
  355.  
  356.     if( !exists $parent->{KidHash} ) {
  357.         my $kh = Ast::New( "LookupTable" );
  358.         $parent->AddProp( "KidHash", $kh );
  359.     }
  360.  
  361.     $parent->{KidHash}->AddProp( $child->{astNodeName},
  362.         $child );
  363. }
  364.  
  365. =head2 makeClassList
  366.  
  367.     Parameters: node, outlist ref
  368.  
  369.     fills outlist with a sorted list of all direct, non-external
  370.     compound children of node.
  371.  
  372. =cut
  373.  
  374. sub makeClassList
  375. {
  376.     my ( $rootnode, $list ) = @_;
  377.  
  378.     @$list = ();
  379.  
  380.     Iter::LocalCompounds( $rootnode,
  381.         sub { 
  382.                 my $node = shift;
  383.  
  384.                 my $her = join ( "::", heritage( $node ) );
  385.                 $node->AddProp( "FullName", $her );
  386.  
  387.                 if ( !exists $node->{DocNode}->{Internal} ||
  388.                      !$main::skipInternal ) {
  389.                     push @$list, $node;
  390.                 }
  391.     } );
  392.  
  393.     @$list = sort { $a->{FullName} cmp $b->{FullName} } @$list;
  394. }
  395.  
  396. #
  397. # Debugging utilities
  398. #
  399.  
  400. =head2 dumpAst
  401.  
  402.     Parameters: node, deep
  403.     Returns: none
  404.  
  405.     Does a recursive dump of the node and its children.
  406.     If deep is set, it is used as the recursion property, otherwise
  407.     "Kids" is used.
  408.  
  409. =cut
  410.  
  411. sub dumpAst
  412. {
  413.     my ( $node, $deep ) = @_;
  414.  
  415.     $deep = "Kids" if !defined $deep;
  416.  
  417.     print "\t" x $depth, $node->{astNodeName}, 
  418.         " (", $node->{NodeType}, ")\n";
  419.  
  420.     my $kid;
  421.  
  422.     foreach $kid ( $node->GetProps() ) {
  423.         print "\t" x $depth, "  -\t", $kid, " -> ", $node->{$kid},"\n"
  424.             unless $kid =~ /^(astNodeName|NodeType|$deep)$/;
  425.     }
  426.     if ( exists  $node->{InList} ) {
  427.         print "\t" x $depth, "  -\tAncestors -> ";
  428.         foreach my $innode ( @{$node->{InList}} ) {
  429.             print $innode->{astNodeName} . ",";
  430.         }
  431.         print "\n";
  432.     }
  433.  
  434.     print "\t" x $depth, "  -\n" if (defined $node->{ $deep } && scalar(@{$node->{ $deep }}) != 0);
  435.  
  436.     $depth++;
  437.     foreach $kid ( @{$node->{ $deep }} ) {
  438.         dumpAst( $kid );
  439.     }
  440.  
  441.     print "\t" x $depth, "Documentation nodes:\n" if defined 
  442.         @{ $node->{Doc}->{ "Text" }};
  443.  
  444.     foreach $kid ( @{ $node->{Doc}->{ "Text" }} ) {
  445.         dumpAst( $kid );
  446.     }
  447.  
  448.     $depth--;
  449. }
  450.  
  451. =head2 testRef
  452.  
  453.     Parameters: rootnode
  454.  
  455.     Interactive testing of referencing system. Calling this
  456.     will use the readline library to allow interactive entering of
  457.     identifiers. If a matching node is found, its node name will be
  458.     printed.
  459.  
  460. =cut
  461.  
  462. sub testRef {
  463.     require Term::ReadLine;
  464.  
  465.     my $rootNode = $_[ 0 ];
  466.  
  467.     my $term = new Term::ReadLine 'Testing findRef';
  468.  
  469.     my $OUT = $term->OUT || *STDOUT{IO};
  470.     my $prompt = "Identifier: ";
  471.  
  472.     while( defined ($_ = $term->readline($prompt)) ) {
  473.  
  474.         my $node = kdocAstUtil::findRef( $rootNode, $_ );
  475.  
  476.         if( defined $node ) {
  477.             print $OUT "Reference: '", $node->{astNodeName}, 
  478.             "', Type: '", $node->{NodeType},"'\n";
  479.         }
  480.         else {
  481.             print $OUT "No reference found.\n";
  482.         }
  483.  
  484.         $term->addhistory( $_ ) if /\S/;
  485.     }
  486. }
  487.  
  488. sub printDebugStats
  489. {
  490.     print "findRef: ", $refcalls, " calls, ", 
  491.         $refiters, " iterations.\n";
  492. }
  493.  
  494. sub External
  495. {
  496.     return defined $_[0]->{ExtSource};
  497. }
  498.  
  499. sub Compound
  500. {
  501.     return defined $_[0]->{Compound};
  502. }
  503.  
  504. sub localComp
  505. {
  506.     my ( $node ) = $_[0];
  507.     return defined $node->{Compound} 
  508.         && !defined $node->{ExtSource} 
  509.         && $node->{NodeType} ne "Forward";
  510. }
  511.  
  512. sub hasDoc
  513. {
  514.     return defined $_[0]->{DocNode};
  515. }
  516.  
  517. ### Warning: this returns the list of parents, e.g. the 3 words in KParts::ReadOnlyPart::SomeEnum
  518. ### It has nothing do to with inheritance.
  519. sub heritage
  520. {
  521.         my $node = shift;
  522.         my @heritage;
  523.  
  524.         while( 1 ) {
  525.             push @heritage, $node->{astNodeName};
  526.  
  527.             last unless defined $node->{Parent};
  528.             $node = $node->{Parent};
  529.             last unless defined $node->{Parent};
  530.         }
  531.  
  532.         return reverse @heritage;
  533. }
  534.  
  535.  
  536. 1;
  537.